package com.inno.subject.controller.aspect;

import cn.hutool.extra.spring.SpringUtil;


import com.inno.subject.common.annotiation.Log;
import com.inno.subject.common.context.LoginUserContext;
import com.inno.subject.common.entity.OperationLog;
import com.inno.subject.common.utils.DateUtils;
import eu.bitwalker.useragentutils.UserAgent;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.lang.reflect.Method;
import java.util.Objects;

/**
 * @author shenzeyang
 */
@Component
@Aspect
@Slf4j
public class LogAspect {
    private static final String TOPIC = "save-log";

    private final RocketMQTemplate rocketMQTemplate;
    public LogAspect(RocketMQTemplate mqTemplate){
        this.rocketMQTemplate = mqTemplate;
        log.info("LogAspect init .. mq:{}",rocketMQTemplate);
    }

    @Pointcut("@annotation(com.inno.subject.common.annotiation.Log)")
    public void pointcut() {
    }

    @Around("pointcut()")
    public Object doAround(ProceedingJoinPoint point) throws Throwable {
        OperationLog operationLog = new OperationLog();
        // 获取注解参数

        Method method = ((MethodSignature) point.getSignature()).getMethod();
        Log logEnum = method.getAnnotation(Log.class);
        String operationType = logEnum.operationType();

        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        String ip = getClientIp(request);
        operationLog.setOperationIp(ip);
        operationLog.setOperationType(operationType);
        Long userId = LoginUserContext.getUserId();
        operationLog.setUserId(userId);
        operationLog.setOperationEquipment(getEquipment(request));
        operationLog.setCreateTime(DateUtils.getNowDate());
        String methodTrace = method.getDeclaringClass().getName() + "." + method.getName();
        operationLog.setMethodTrace(methodTrace);
        operationLog.setServiceName(SpringUtil.getApplicationName());
        StopWatch watch = new StopWatch();
        Object proceed = null;
        try {
            watch.start();
            proceed = point.proceed();
            return proceed;
        }catch (Throwable e){
            operationLog.setErrorMsg(e.getMessage());
        }finally {
            watch.stop();
            operationLog.setTakeTime(watch.getTotalTimeMillis());
            this.rocketMQTemplate.convertAndSend(TOPIC, operationLog);
        }
        return proceed;
    }
    public static String getClientIp(HttpServletRequest request) {
        if (request == null) {
            return StringUtils.EMPTY;
        }
        String ip = request.getHeader("X-Forwarded-For");
        final String unknown = "unknown";
        if (StringUtils.isNotEmpty(ip) && !unknown.equalsIgnoreCase(ip)) {
            //多次反向代理后会有多个ip值，第一个ip才是真实ip
            int index = ip.indexOf(",");
            if (index != -1) {
                return ip.substring(0, index);
            } else {
                return ip;
            }
        }
        ip = request.getHeader("X-Real-IP");
        if (StringUtils.isEmpty(ip) || unknown.equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
            if (StringUtils.isBlank(ip)) {
                ip = request.getHeader("WL-Proxy-Client-IP");
            }
            if (StringUtils.isBlank(ip)) {
                ip = request.getHeader("HTTP_CLIENT_IP");
            }
            if (StringUtils.isBlank(ip)) {
                ip = request.getHeader("HTTP_X_FORWARDED_FOR");
            }
            if (StringUtils.isBlank(ip)) {
                ip = request.getRemoteAddr();
            }
        }
        return ip;
    }
    public static String getEquipment(HttpServletRequest request) {
        UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("user-agent"));
        //客户端类型  手机、电脑、平板
        String clientType = userAgent.getOperatingSystem().getDeviceType().toString();

        //操作系统类型
        String os = userAgent.getOperatingSystem().getName();

        //浏览器类型
        String browser = userAgent.getBrowser().toString();


        return clientType + ":" + os + ":" + browser ;

    }

}
